package com.je.app.control;

import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import com.je.app.control.interfaces.ControlSesionInterface;
import com.je.app.model.Consumicion;
import com.je.app.model.Habitacion;
import com.je.app.model.Movimiento;
import com.je.app.model.Observacion;
import com.je.app.model.Sesion;
import com.je.app.model.Turno;
import com.je.app.model.Usuario;
import com.je.app.persistence.DaoHabitacion;
import com.je.app.persistence.DaoSesion;
import com.je.app.persistence.DaoStock;
import com.je.app.persistence.HibernateUtil;
import com.je.app.view.DatosPersonales;
import com.je.app.view.MainFrame;
import com.je.app.view.MainFrame.MessageType;
import com.je.app.view.ResultadosMensuales;
import com.je.app.view.Sesiones;
import com.je.app.view.popUp.MostrarUsuariosNoAdmitidos;
import com.je.app.view.popUp.ValidarUsuario;

public class ControlSesion implements ControlSesionInterface {

	private static ControlSesion instance = new ControlSesion();

	private MainFrame mainFrame ;
	private DaoSesion daoSesion = DaoSesion.getInstance();
	private Sesion activeSesion;

	private List <Usuario> listaUsuariosNoAdmitidos;

	private List <Sesion> sesiones;

	private List <Usuario> usuarios;

	public static ControlSesion getInstance(){
		
		return instance;
	}
	
	private ControlSesion(){
		//cerrar sesiones anteriores abiertas.
		List <Sesion> sesiones = daoSesion.sesionesAbiertas();
		for(Sesion sesion: sesiones){
			sesion.setHoraFin(new Date());
			daoSesion.persist(sesion);
		}
	}

	public Sesion getActiveSesion() {
		return activeSesion;
	}
	
	public void validarUsuario(String idUsuario, String contrasenia, ValidarUsuario dialog){
		Usuario usuario = daoSesion.validate(idUsuario, contrasenia); 
		
		if(usuario==null || !usuario.isAdmitido()){
			
			if(dialog==null){
				JDialog validar = new ValidarUsuario();
				((ValidarUsuario) validar).errorVisible();
			}
			else{
				dialog.errorVisible();
			}
		}
		else{
			double cajaInicial = daoSesion.cajaUltimaSesion();
			activeSesion = new Sesion(0,usuario,cajaInicial,cajaInicial,new Date());
			daoSesion.save(Sesion.class.getName(),activeSesion);
			ControlHabitacion.getInstance().abrirPanelHabitaciones();
			dialog.dispose();
			mainFrame = MainFrame.getInstance();
			mainFrame.setVisible(true);
			
			if(usuario.isAdministrador()){
				mostrarNuevosUsuarios();
			}

		}
	}

	private void mostrarNuevosUsuarios() {
		//buscar en el DAO todos los usuarios
		
		List <Usuario> listaUsuariosCompleta = daoSesion.list(Usuario.class.getName());
		
		//filtrar los usuario  con admitido = 0
		//mantener una lista ordenada. 
		//NOTA: si se cancela o acepta el usuario, eliminar de la lista y de la tabla en pantalla.
		listaUsuariosNoAdmitidos = new ArrayList <Usuario> ();
		for(Usuario usuarioAux : listaUsuariosCompleta){
			if(!usuarioAux.isAdmitido()){
				listaUsuariosNoAdmitidos.add(usuarioAux);
			}
		}

		//crear matriz
		int cantidadFilas = listaUsuariosNoAdmitidos.size();
		String [][] matrizUsuariosNoAdmitidos = new String [cantidadFilas][2];
		
		int index = 0;
		for(Usuario usuarioAux : listaUsuariosNoAdmitidos){
			String [] filaNueva = new String []{usuarioAux.getIdUsuario(),usuarioAux.getNombre() + " " + usuarioAux.getApellido()};
			matrizUsuariosNoAdmitidos[index] = filaNueva;
			index++;
		}

		//si hay usuario no admitidos pasar como parametro al JDialog
		if(index>0)
			new MostrarUsuariosNoAdmitidos(matrizUsuariosNoAdmitidos);
		
	}

	public void admitirUsuario(int filaUsuario){
		//buscar usuario en la listaUsuarios mantenida
		Usuario usuarioAdmitido = listaUsuariosNoAdmitidos.get(filaUsuario);
		
		//setear el valor admitido = true
		usuarioAdmitido.setAdmitido(true);
		
		//guardar los cambios mediante el dao
		daoSesion.persist(usuarioAdmitido);
		
 		//eliminar usuario de la listaUsuarios mantenida y de la tabla en pantalla
		listaUsuariosNoAdmitidos.remove(filaUsuario);
	}
	
	public void rechazarUsuario(int filaUsuario){
		//buscar usuario en la listaUsuarios mantenida
		Usuario usuarioAdmitido = listaUsuariosNoAdmitidos.get(filaUsuario);
		
		//eliminar mediante el dao
		daoSesion.remove(usuarioAdmitido);
		
		//eliminar de la listaMantenida y de la tabla en pantalla
		listaUsuariosNoAdmitidos.remove(filaUsuario);
	}
	
	public void cerrarSesion() {
		activeSesion.setHoraFin(new Date());
		daoSesion.persist(activeSesion);

		//CUERPO DEL EMAIL -> USUARIO, SALDO INICIAL, SALDO FINAL, FECHA INICIO, FECHA FIN, CANTIDAD TURNOS, STOCKS.
		
		String asunto = "FINALIZ\u00D3 UNA SESI\u00D3N";

		String cuerpo = "Usuario: " + activeSesion.getUsuario().getNombre() + " " + activeSesion.getUsuario().getApellido();
		cuerpo = cuerpo + ".\n\nFecha inicio: " + activeSesion.getHoraInicio().toLocaleString();
		cuerpo = cuerpo + ".\nFecha fin: " + activeSesion.getHoraFin().toLocaleString();
		cuerpo = cuerpo + ".\n\nSaldo inicial: " + activeSesion.getCajaInicial();
		cuerpo = cuerpo + ".\nSaldo final: " + activeSesion.getCajaFinal();
		cuerpo = cuerpo + ".\n\nCantidad turnos: " + activeSesion.getTurnos().size();
		cuerpo = cuerpo + ".\n\nEstado actual de Stock:";
		
		List <Consumicion> list = DaoStock.getInstance().list(Consumicion.class.getName());
		
		for(Consumicion cons : list){
			cuerpo = cuerpo + "\n\nNombre: " + cons.getNombre();
			cuerpo = cuerpo + ".\nPrecio: " + cons.getPrecioUnitario();
			cuerpo = cuerpo + ".\nEn heladera: " + cons.getStockHeladera();
			cuerpo = cuerpo + ".\nEn dep\u00F3sito: " + cons.getStockDeposito() + "."; 	
		}

		EnvioMail envio = new EnvioMail(asunto, cuerpo, null);
		envio.start();

		activeSesion=null;
		mainFrame.dispose();
		HibernateUtil.getSession().disconnect();
		HibernateUtil.getSessionFactory().close();

		
	}
	
	public void setActiveSesion(Sesion sesion) {
		this.activeSesion = sesion;
		
	}

	public void mostrarSesiones(){
		//info de tabla sesiones -> Usuario, fecha, hora inicio, hora fin, caja inicial, caja final.

		sesiones = daoSesion.list();
		usuarios = daoSesion.list("Usuario");
		
		String [] listaUsuarios = new String[usuarios.size()+1];
		String [][] matrizSesiones = new String [sesiones.size()][6];
		listaUsuarios[0] = "Todos";
		for(int i = 1 ; i <= usuarios.size() ; i++){
			listaUsuarios[i] =
					usuarios.get(i-1).getNombre() + " " + usuarios.get(i-1).getApellido();
		}
		
		for(int i = 0 ; i < sesiones.size() ; i++){
			matrizSesiones[i] = sesiones.get(i).toArray();
		}
		
		//pasar matriz como parametro a JPanel
		mainFrame.setPanel(new Sesiones(matrizSesiones, listaUsuarios));
	}
	
	public void buscarSesiones(Date fecha, int filaUsuario){
		String idUsuario = null;
		if(filaUsuario>0){
			idUsuario = usuarios.get(filaUsuario-1).getIdUsuario();
		}
		if(idUsuario!=null || fecha != null){
			sesiones = daoSesion.filter(fecha,idUsuario);
			List <Object []> matrizSesiones = new ArrayList <Object []> ();
			for(int i = 0 ; i < sesiones.size() ; i++){
				matrizSesiones.add(sesiones.get(i).toArray());
			}
			mainFrame.setTableModel("sesiones", matrizSesiones);
		}
		else{
			mostrarSesiones();
		}
	}
	
	public void mostrarInformacionSesion(int filaSesion){
		// info de sesion selecc -> Ingresos (Detalle, monto), Egresos (Detalle, monto), Turnos (habitacion, Inicio, Fin, monto x 3)
		Sesion sesionSeleccionada = sesiones.get(filaSesion);
		Set <Turno> turnos = sesionSeleccionada.getTurnos();
		Set <Movimiento> movimientos = sesionSeleccionada.getMovimientos();
		List <Object []> matrizTurnos = new ArrayList <Object[]>();

		for(Turno turnoAux : turnos){
			matrizTurnos.add(turnoAux.getArray());	
		}
		
		double totalTurnos = 0;
		double totalEntradas = 0;
		double totalSalidas = 0;
		
		List <Object[]> modelEntradas = new ArrayList <Object[]>();
		List <Object[]> modelSalidas = new ArrayList <Object[]>();
		
		for(Movimiento movimiento: movimientos){
			if(movimiento.getTipoMovimiento().equals("Ingreso")){
				modelEntradas.add(movimiento.toArray());
				totalEntradas += movimiento.getMonto();
			}else{
				totalSalidas += movimiento.getMonto();
				modelSalidas.add(movimiento.toArray());
			}
		}
			
		totalTurnos = Math.floor(totalTurnos * 100)/100;
		totalEntradas = Math.floor(totalEntradas * 100)/100;
		totalSalidas = Math.floor(totalSalidas * 100)/100;
		
		//pasar matrices y valores mediante seteos a JPanel
		mainFrame.setProperty("totalTurnos", totalTurnos);
		mainFrame.setProperty("totalIngresos", totalEntradas);
		mainFrame.setProperty("totalEgresos", totalSalidas);
		mainFrame.setTableModel("egresos", modelSalidas);
		mainFrame.setTableModel("ingresos", modelEntradas);
		mainFrame.setTableModel("turnos",matrizTurnos);	
	}
	
	public boolean registrarUsuario(String id, String nombre, String apellido, String contrasenia, String contraseniaRepeticion){
		//crear la entidad
		//administrador = 0, admitido = 0.
		Usuario usuario = new Usuario(id,contrasenia,nombre,apellido,false,false);
		
		try{
			if(!contrasenia.equals(contraseniaRepeticion)){
				//ERROR -> LAS CONTRASENIAS DEBEN SER IGUALES
				Toolkit.getDefaultToolkit().beep(); 
				JOptionPane.showMessageDialog(null, "Las contrase\u00F1as ingresadas no son iguales"
						,"Mensaje de error", JOptionPane.ERROR_MESSAGE);
			
				return false;
			}
			
			if(!daoSesion.validarIdUnico(id)){
				Toolkit.getDefaultToolkit().beep(); 
				JOptionPane.showMessageDialog(null, "Id no permitido"
						,"Mensaje de error", JOptionPane.ERROR_MESSAGE);
				
				return false;
			}
			
			if(!daoSesion.validarNombreApellidoUnico(nombre,apellido,"-1")){
				Toolkit.getDefaultToolkit().beep(); 
				JOptionPane.showMessageDialog(null, "Ya existe un usuario con este nombre y apellido"
						,"Mensaje de error", JOptionPane.ERROR_MESSAGE);

				return false;
			}
			

			//persistirla
			daoSesion.save("Usuario", usuario);
			return true;
			
		}
		catch(ConstraintViolationException cve){

			//mensajes error
			cve.printStackTrace();
			Toolkit.getDefaultToolkit().beep(); 
			HibernateUtil.getSession().getTransaction().rollback();
			for(ConstraintViolation constraintViolation : cve.getConstraintViolations()){
				
				JOptionPane.showMessageDialog(null, "En el campo " + constraintViolation.getPropertyPath().toString() + ": " 
				+ constraintViolation.getMessage(),"Mensaje de error", JOptionPane.ERROR_MESSAGE);
			}
			
			return false;

		}		
	}
		public void mostrarDatosPersonales(){
			
			Usuario usuarioLogueado = ControlSesion.getInstance().getActiveSesion().getUsuario();
			
			MainFrame.getInstance().setPanel(new DatosPersonales(usuarioLogueado.getIdUsuario(),
			usuarioLogueado.getNombre(),
			usuarioLogueado.getApellido(),
			usuarioLogueado.getContrasenia()));
			
		}
		
		public boolean modificarDatosPersonales(String nombre, String apellido, String contrasenia){
			Usuario usuarioLogueado = ControlSesion.getInstance().getActiveSesion().getUsuario();
			boolean validado = daoSesion.validarNombreApellidoUnico(nombre, apellido, usuarioLogueado.getIdUsuario());
			if(!validado){
				mainFrame.showMessage(MessageType.ERROR,"Existe un usuario con este nombre y apellido");
				//NOMBRE Y APELLIDO NO VALIDOS
				return false;
			}
			else if(nombre.length()>45 || nombre.length()<3){
				mainFrame.showMessage(MessageType.ERROR,"El nombre debe tener entre 3 y 45 caracteres");
				//NOMBRE CON CANTIDAD DE CARACTERES INVALIDO
				return false;
			}
			else if(apellido.length()>45 || apellido.length()<3){
				mainFrame.showMessage(MessageType.ERROR,"El apellido debe tener entre 3 y 45 caracteres");
				//APELLIDO CON CANTIDAD DE CARACTERES INVALIDO
				return false;
			}
			else if(contrasenia.length()>45 || contrasenia.length()<3){
				mainFrame.showMessage(MessageType.ERROR,"La contrase\u00F1a debe tener entre 3 y 45 caracteres");
				//CONTRASENIA CON CANTIDAD DE CARACTERES INVALIDO				
				return false;
			}
			else{				
				usuarioLogueado.setApellido(apellido);
				usuarioLogueado.setNombre(nombre);
				usuarioLogueado.setContrasenia(contrasenia);
				daoSesion.persist(usuarioLogueado);
				return true;
				}			
		}

		public void mostrarResultadosMensuales() {
			Object[][] matriz = daoSesion.obtenerResultadosMensuales();
			MainFrame.getInstance().setPanel(new ResultadosMensuales(matriz));
			
		}

		public List<Object[]> obtenerObservaciones(String nombreHab) {
			List <Observacion> observaciones = daoSesion.listaObservaciones(nombreHab);
			List <Object[]> lista = new ArrayList <Object[]>();
			
			for(Observacion obs : observaciones){
				lista.add(obs.toArray());
			}
			return lista;
		}
		
	    public static void main (String [] args){
	        new ValidarUsuario();
	}



	
}
